<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button class="btn">click</button>
    <!-- <script>

        // bind 的基本使用
        // 

        var x = 10;
        function show() {
            // 函数是由 Function 构造的，也是对象
            console.log(this.x);
        }
        show();

        var obj = {
            x: 20
        };

        var newShow = show.bind(obj);
        // bind函数返回一个新的函数，新的函数还是执行一样的功能，只是this指向obj
        newShow();

    </script> -->

    <!-- <script>
        // bind 的例子
        // 单对象编程，即常用的封装方法，把变量放进对象，通过调用对象的方法实现功能
        var list = {
            init: function() {
                this.dom = document.getElementsByClassName('btn')[0];
                this.ms = 'duyi';
                this.bindEvent();
            },
            bindEvent: function() {
                // this.dom.onclick = this.showMessage;
                this.dom.onclick = this.showMessage.bind(this);
                // 和call、apply还是有区别的，call必须是执行的时候才能改变this指向
            },
            showMessage: function() {
                console.log(this.ms);
            }
        }
        list.init();
    </script> -->

    <!-- <script>
        var x = 10;
        function show(a, b) {
            // console.log(a);
            console.log(this.x, a, b);
        }
        show('a', 'b');

        var obj = {
            x: 20
        }

        var newShow = show.bind(obj, 'c');
        // 后面传的参数会在执行时，拼到实参的前面
        newShow('d'); // 相当于传的newShow('c', 'd');  



    </script> -->
    <!-- <script>    
        var list = {
            init: function() {
                this.dom = document.getElementsByClassName('btn')[0];
                this.ms = 'duyi';
                this.bindEvent();
            },
            bindEvent: function() {
                this.dom.onclick = this.showMessage.bind(this, 'hello', 'world');
                // 事件函数可以这样传参
            },
            showMessage: function(info1, info2, e) {
                console.log(this.ms, info1, info2, e);
            }
        }
        list.init();


        // 总结：
        // function A() {

        // }
        // var o = {}
        // var x = 1;
        // var y = 2;
        // var z = 3;
        // var B = A.bind(o, x, y);
        // B('c');,其实执行的还是函数A

        // 1. 函数A调用bind方法时，需要传递的参数o , x, y, z...
        // 2. 返回新的函数B
        // 3. 函数B执行的时候，具体的功能实际上还是使用的A，只不过this指向变成了o
        // 4. 函数B在执行的时候，你传递的参数会拼接到 x, y, z 的后面，一并在内部传递给A执行
        // 5. 通过 new B() 生成对象，构造函数依旧是A，并且 o 不会起到任何作用（不会在改变this指向）
    
        // var x = 10;
        // function show() {
        //     console.log(this.x);
        // }
        // show();

        // var obj = {
        //     x: 20
        // }

        // var newShow = show.bind(obj);
        // console.log(new newShow().constructor); //打印出函数show

    </script> -->

    <script>
        Function.prototype.newBind = function(target) {
            // target 改变返回函数执行的this指向

            var that = this;
            var args = [].slice.call(arguments, 1);
            // 类数组可以通过这样进行截取，返回数组
            var temp = function(){};
            var f = function() {
                var _arg = [].slice.call(arguments, 0);
                //真正执行的其实是 that
                return that.apply(this instanceof temp ? this : (target || window), args.concat(_arg));//没传参数会使用window
            }
            temp.prototype = that.prototype;
            f.prototype = new temp();

            return f;
        }

        function show(x, y, z, w) {
            console.log(this, x, y, z, w);
        }
        var obj = {
            x: 20
        }

        var newShow = show.newBind(obj, 1, 2, 3);
        newShow(4);

        console.log(new newShow());

    </script>
</body>
</html>